from datetime import datetime

from nebula3.common.ttypes import Value, DateTime

from server.config.graph_database import graph_session
from server.module_chat.business.flfj.dao.flfj_dao import FlfjDao
from server.utils.md5_util import MD5Util
from server.utils.string_util import StringUtil
from server.utils.log_util import logger


class FlfjService:

    @classmethod
    async def build_graph(cls):
        """
        构建分类分级知识图谱
        """

        # 构建数据资源知识图谱
        await cls.build_resource_graph()

        # 构建数据资源清单知识图谱
        await cls.build_data_resource_graph()

        # 构建数据目录知识图谱
        await cls.build_data_directory_graph()

    @classmethod
    async def build_resource_graph(cls):
        # 构建业务系统->数据库/文件系统知识图谱
        resource_list = await FlfjDao.get_resource_list()
        for resource in resource_list:
            id = resource.id
            resource_name = resource.resource_name or ''
            resource_type = resource.resource_type or ''
            database_schema = resource.database_schema or ''
            system_name = resource.system_name or ''
            data_owner = resource.data_owner or ''
            data_manager = resource.data_manager or ''
            create_time = Value(dtVal=cls.format_date(resource.create_time))
            update_time = Value(dtVal=(cls.format_date(resource.update_time or resource.create_time)))

            # 构建业务系统知识图谱
            if not StringUtil.is_empty(system_name):
                v_business_system_id = "system_" + MD5Util.md5_16(system_name)
                business_system_args = {
                    "system_name": system_name,
                    "data_owner": data_owner,
                    "data_manager": data_manager
                }
                stmt = ("INSERT VERTEX business_system(name, data_owner, data_manager) "
                        "VALUES '{}':($system_name, $data_owner, $data_manager);").format(v_business_system_id)
                cls.graph_execute(stmt, business_system_args)

            # 构建文件系统知识图谱
            if resource_type == '5':
                file_system_id = id
                file_system_name = resource_name
                v_file_system_id = "file_system_" + str(file_system_id)

                file_system_args = {
                    "file_system_id": file_system_id,
                    "file_system_name": file_system_name,
                    "data_owner": data_owner,
                    "data_manager": data_manager,
                    "create_time": create_time,
                    "update_time": update_time
                }

                stmt = (
                    "INSERT VERTEX file_system(file_system_id, name, data_owner, "
                    "data_manager, create_time, update_time) "
                    "VALUES '{}':($file_system_id, $file_system_name, $data_owner, "
                    "$data_manager, $create_time, $update_time);"
                ).format(v_file_system_id)
                cls.graph_execute(stmt, file_system_args)

                if not StringUtil.is_empty(system_name):
                    edge_stmt = "INSERT EDGE contains() VALUES '{}'->'{}':();".format(v_business_system_id,
                                                                                      v_file_system_id)
                    cls.graph_execute(edge_stmt, {})

            # 构建数据库知识图谱
            elif resource_type == '6':
                database_id = id
                database_name = resource_name
                v_database_id = "database_" + str(database_id)

                database_args = {
                    "database_id": database_id,
                    "database_name": database_name,
                    "database_schema": database_schema,
                    "data_owner": data_owner,
                    "data_manager": data_manager,
                    "create_time": create_time,
                    "update_time": update_time
                }

                stmt = (
                    "INSERT VERTEX database(database_id, name, database_schema, "
                    "data_owner, data_manager, create_time, update_time) "
                    "VALUES '{}':($database_id, $database_name, $database_schema, "
                    "$data_owner, $data_manager, $create_time, $update_time);"
                ).format(v_database_id)
                cls.graph_execute(stmt, database_args)

                if not StringUtil.is_empty(system_name):
                    edge_stmt = "INSERT EDGE contains() VALUES '{}'->'{}':();".format(v_business_system_id,
                                                                                      v_database_id)
                    cls.graph_execute(edge_stmt, {})

    @classmethod
    async def build_data_resource_graph(cls):
        id_object = await FlfjDao.count_data_resource()

        min_id = id_object.get("min_id")
        max_id = id_object.get("max_id")

        page_size = 1000

        for start_id in range(min_id, max_id, page_size):
            end_id = min(start_id + page_size, max_id)

            data_resource_list = await FlfjDao.get_data_resource_list(start_id=start_id, end_id=end_id)

            # 处理每页的结果
            for data_resource in data_resource_list:
                id = data_resource.id
                task_type = data_resource.task_type
                resource_id = data_resource.resource_id
                resource_name = data_resource.resource_name or ''
                database_schema = data_resource.database_schema or ''
                database_table = data_resource.database_table or ''
                file_name = data_resource.file_name or ''
                field_name = data_resource.field_name or ''
                data_owner = data_resource.data_owner or ''
                data_manager = data_resource.data_manager or ''
                create_time = Value(dtVal=cls.format_date(data_resource.create_time))
                update_time = Value(dtVal=cls.format_date(data_resource.update_time or data_resource.create_time))

                # 构建文件知识图谱
                if task_type == 2 or task_type == 5:
                    file_id = id
                    v_file_id = "file_" + str(file_id)

                    file_args = {
                        "file_id": file_id,
                        "file_name": file_name,
                        "data_owner": data_owner,
                        "data_manager": data_manager,
                        "data_category_1": '',
                        "data_category_2": '',
                        "data_category_3": '',
                        "data_category_4": '',
                        "data_level": '',
                        "create_time": create_time,
                        "update_time": update_time
                    }
                    stmt = (
                        "INSERT VERTEX file("
                        "file_id, name, data_owner, data_manager, "
                        "data_category_1, data_category_2, data_category_3, data_category_4, "
                        "data_level, create_time, update_time) "
                        "VALUES '{}':($file_id, $file_name, $data_owner, $data_manager, "
                        "$data_category_1, $data_category_2, $data_category_3, $data_category_4, "
                        "$data_level, $create_time, $update_time);"
                    ).format(v_file_id)
                    cls.graph_execute(stmt, file_args)

                    if resource_id:
                        v_file_system_id = "file_system_" + str(resource_id)
                        edge_stmt = "INSERT EDGE contains() VALUES '{}'->'{}':();".format(v_file_system_id, v_file_id)
                        cls.graph_execute(edge_stmt, {})

                # 构建数据库表和数据库字段知识图谱
                elif task_type == 6 or task_type == 7:
                    # 构建数据库表知识图谱
                    if task_type == 6:
                        table_id = id
                        table_name = database_table
                        v_table_id = "table_" + MD5Util.md5_16(str(resource_id) + str(table_name))

                        table_args = {
                            "table_id": table_id,
                            "table_name": table_name,
                            "data_owner": data_owner,
                            "data_manager": data_manager,
                            "data_category_1": '',
                            "data_category_2": '',
                            "data_category_3": '',
                            "data_category_4": '',
                            "data_level": '',
                            "create_time": create_time,
                            "update_time": update_time
                        }

                        stmt = (
                            "INSERT VERTEX table(table_id, name, data_owner, data_manager, "
                            "data_category_1, data_category_2, data_category_3, data_category_4, "
                            "data_level, create_time, update_time) "
                            "VALUES '{}':($table_id, $table_name, $data_owner, $data_manager, "
                            "$data_category_1, $data_category_2, $data_category_3, $data_category_4, "
                            "$data_level, $create_time, $update_time);"
                        ).format(v_table_id)
                        cls.graph_execute(stmt, table_args)

                        if resource_id:
                            v_database_id = "database_" + str(resource_id)
                            edge_stmt = "INSERT EDGE contains() VALUES '{}'->'{}':();".format(v_database_id, v_table_id)
                            cls.graph_execute(edge_stmt, {})

                    # 构建数据库字段知识图谱
                    if task_type == 7:
                        field_id = id
                        table_name = database_table
                        v_field_id = "field_" + str(field_id)
                        v_table_id = "table_" + MD5Util.md5_16(str(resource_id) + str(table_name))

                        field_args = {
                            "field_id": field_id,
                            "field_name": field_name,
                            "data_owner": data_owner,
                            "data_manager": data_manager,
                            "data_category_1": '',
                            "data_category_2": '',
                            "data_category_3": '',
                            "data_category_4": '',
                            "data_level": '',
                            "create_time": create_time,
                            "update_time": update_time
                        }

                        table_stmt = (
                            "INSERT VERTEX IF NOT EXISTS table(table_id, name, data_owner, data_manager) "
                            "VALUES '{}':(0, '{}', '{}', '{}');"
                        ).format(v_table_id, table_name, data_owner, data_manager)
                        cls.graph_execute(table_stmt, {})

                        if resource_id:
                            v_database_id = "database_" + str(resource_id)
                            edge_stmt = "INSERT EDGE contains() VALUES '{}'->'{}':();".format(v_database_id, v_table_id)
                            cls.graph_execute(edge_stmt, {})

                        field_stmt = (
                            "INSERT VERTEX IF NOT EXISTS field(field_id, name, data_owner, data_manager, "
                            "data_category_1, data_category_2, data_category_3, data_category_4, data_level, "
                            "create_time, update_time) "
                            "VALUES '{}':($field_id, $field_name, $data_owner, $data_manager, "
                            "$data_category_1, $data_category_2, $data_category_3, $data_category_4, $data_level, "
                            "$create_time, $update_time);"
                        ).format(v_field_id)
                        cls.graph_execute(field_stmt, field_args)

                        edge_stmt = "INSERT EDGE contains() VALUES '{}'->'{}':();".format(v_table_id, v_field_id)
                        cls.graph_execute(edge_stmt, {})

    @classmethod
    async def build_data_directory_graph(cls):
        id_object = await FlfjDao.count_data_directory()

        min_id = id_object.get("min_id")
        max_id = id_object.get("max_id")

        page_size = 1000

        for start_id in range(min_id, max_id, page_size):
            end_id = min(start_id + page_size, max_id)

            data_directory_list = await FlfjDao.get_data_directory_list(start_id=start_id, end_id=end_id)

            # 处理每页的结果
            for data_directory in data_directory_list:
                task_type = data_directory.task_type
                resource_id = data_directory.resource_id
                resource_name = data_directory.resource_name or ''
                system_name = data_directory.system_name or ''
                scan_id = data_directory.scan_id
                data_owner = data_directory.data_owner or ''
                data_manager = data_directory.get("data_manager") or ''
                file_name = data_directory.get("file_name") or ''
                field_name = data_directory.get("field_name") or ''
                data_category_1 = data_directory.get("data_category_1") or ''
                data_category_2 = data_directory.get("data_category_2") or ''
                data_category_3 = data_directory.get("data_category_3") or ''
                data_category_4 = data_directory.get("data_category_4") or ''
                data_level = data_directory.get("data_level") or ''
                create_time = Value(dtVal=cls.format_date(data_directory.create_time))
                update_time = Value(dtVal=cls.format_date(data_directory.update_time or data_directory.create_time))

                # 初始构建数据目录的参数字典
                data_directory_args = {
                    "v_data_directory_id": '',
                    "data_name": '',
                    "task_type": task_type,
                    "system_name": system_name,
                    "data_owner": data_owner,
                    "data_manager": data_manager,
                    "data_category_1": data_category_1,
                    "data_category_2": data_category_2,
                    "data_category_3": data_category_3,
                    "data_category_4": data_category_4,
                    "data_level": data_level,
                    "create_time": create_time,
                    "update_time": update_time
                }

                # 构建文件知识图谱
                if task_type == 2 or task_type == 5:
                    file_id = int(scan_id)
                    v_file_id = "file_" + scan_id

                    file_args = {
                        "file_id": file_id,
                        "file_name": file_name,
                        "data_category_1": data_category_1,
                        "data_category_2": data_category_2,
                        "data_category_3": data_category_3,
                        "data_category_4": data_category_4,
                        "data_level": data_level
                    }
                    stmt = (
                            "UPDATE VERTEX ON file '{}' " + "set" + " data_category_1 = $data_category_1, "
                                                                    "data_category_2 = $data_category_2, data_category_3 = $data_category_3, "
                                                                    "data_category_4 = $data_category_4, data_level = $data_level"
                    ).format(v_file_id)
                    cls.graph_execute(stmt, file_args)

                    data_directory_args["v_data_directory_id"] = v_file_id
                    data_directory_args["data_name"] = file_name

                # 构建数据库表和数据库字段知识图谱
                elif task_type == 6 or task_type == 7:
                    # 构建数据库表知识图谱
                    if task_type == 6:
                        table_id = int(scan_id)
                        table_name = file_name
                        v_table_id = "table_" + MD5Util.md5_16(str(resource_id) + str(table_name))

                        table_args = {
                            "table_id": table_id,
                            "table_name": table_name,
                            "data_category_1": data_category_1,
                            "data_category_2": data_category_2,
                            "data_category_3": data_category_3,
                            "data_category_4": data_category_4,
                            "data_level": data_level
                        }

                        stmt = (
                                "UPDATE VERTEX ON table '{}' " + "set" + " data_category_1 = $data_category_1, "
                                                                         "data_category_2 = $data_category_2, data_category_3 = $data_category_3, "
                                                                         "data_category_4 = $data_category_4, data_level = $data_level"
                        ).format(v_table_id)
                        cls.graph_execute(stmt, table_args)

                        data_directory_args["v_data_directory_id"] = v_table_id
                        data_directory_args["data_name"] = table_name

                    # 构建数据库字段知识图谱
                    if task_type == 7:
                        field_id = int(scan_id)
                        v_field_id = "field_" + scan_id
                        v_table_id = "table_" + MD5Util.md5_16(str(resource_id) + str(file_name))

                        field_args = {
                            "field_id": field_id,
                            "field_name": field_name,
                            "data_category_1": data_category_1,
                            "data_category_2": data_category_2,
                            "data_category_3": data_category_3,
                            "data_category_4": data_category_4,
                            "data_level": data_level
                        }

                        field_stmt = (
                                "UPDATE VERTEX ON field '{}' " + "set" + " data_category_1 = $data_category_1, "
                                                                         "data_category_2 = $data_category_2, data_category_3 = $data_category_3, "
                                                                         "data_category_4 = $data_category_4, data_level = $data_level"
                        ).format(v_field_id)
                        cls.graph_execute(field_stmt, field_args)

                        data_directory_args["v_data_directory_id"] = v_field_id
                        data_directory_args["data_name"] = field_name

                cls.build_data_directory(data_directory_args)

    @classmethod
    def build_data_directory(cls, data_directory_args: dict):
        v_data_directory_id = data_directory_args["v_data_directory_id"]
        dir_stmt = (
            "INSERT VERTEX data_directory"
            "(name, task_type, system_name, data_owner, data_manager, "
            "data_category_1, data_category_2, data_category_3, "
            "data_category_4, data_level, create_time, update_time) "
            "VALUES '{}':($data_name, $task_type, $system_name, $data_owner, $data_manager, "
            "$data_category_1, $data_category_2, $data_category_3, "
            "$data_category_4, $data_level, $create_time, $update_time);"
        ).format(v_data_directory_id)
        cls.graph_execute(dir_stmt, data_directory_args)

    @classmethod
    def graph_execute(cls, stmt: str, args: dict):
        try:
            print(stmt)
            graph_session.execute_py(stmt, args)
        except Exception as e:
            print(e)
            logger.error(f"stmt执行失败: {stmt}，详细错误信息：{e}")

    @classmethod
    def format_date(cls, date_time: datetime):
        if date_time is None:
            return None
        event_datetime_value = DateTime(
            year=date_time.year,
            month=date_time.month,
            day=date_time.day,
            hour=date_time.hour,
            minute=date_time.minute,
            sec=date_time.second
        )
        return event_datetime_value
